/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.cef.core.buffer.base;

import com.inspur.edp.cef.api.RefObject;
import com.inspur.edp.cef.api.buffer.ICefBuffer;
import com.inspur.edp.cef.api.dataType.base.IAccessorCreator;
import com.inspur.edp.cef.api.manager.IBufferManager;
import com.inspur.edp.cef.api.message.CefException;
import com.inspur.edp.cef.api.session.ICefSession;
import com.inspur.edp.cef.api.session.ICefSessionItem;
import com.inspur.edp.cef.core.manager.EntityDataManager;
import com.inspur.edp.cef.entity.accessor.base.IAccessor;
import com.inspur.edp.cef.entity.changeset.AddChangeDetail;
import com.inspur.edp.cef.entity.changeset.IChangeDetail;
import com.inspur.edp.cef.entity.dependenceTemp.DataValidator;
import com.inspur.edp.cef.entity.entity.ICefData;
import com.inspur.edp.cef.entity.entity.IEntityData;
import java.util.Map;

public abstract class BufferManager implements IBufferManager
{
	private ICefSession privateSession;
	protected final ICefSession getSession()
	{
		return privateSession;
	}

	private IAccessorCreator privateAccessorCreator;
	public final IAccessorCreator getAccessorCreator()
	{
		return privateAccessorCreator;
	}

	private String privateEntityType;
	protected final String getEntityType()
	{
		return privateEntityType;
	}

	protected BufferManager(ICefSession session, String entityType, IAccessorCreator accessorCreator)
	{
		DataValidator.checkForNullReference(session, "session");
		DataValidator.checkForEmptyString(entityType, "entityType");
		DataValidator.checkForNullReference(accessorCreator, "accessorCreator");

		privateSession = session;
		privateEntityType = entityType;
		privateAccessorCreator = accessorCreator;
	}

	public final IAccessor initBufferByLevel(String id, int level, boolean isReadonly)
	{
		throw new UnsupportedOperationException();
	}

	public final IAccessor initBuffer_ZeroLevel(IEntityData data, boolean isReadonly)
	{
		java.util.Map<String, java.util.Map<Integer, ICefBuffer>> buffers = getBuffers(getEntityType());

		CefBuffer result = new CefBuffer(createAccessor(data, isReadonly));
		java.util.HashMap<Integer, ICefBuffer> map =new java.util.HashMap<Integer, ICefBuffer>();
		map.put(0,result);
		buffers.put(data.getID(), map);

		return result.getData();
	}

	public final void rejectBufferZeroLevel(String id)
	{
		DataValidator.checkForNullReference(id, "id");

		java.util.Map<String, java.util.Map<Integer, ICefBuffer>> buffers = getBuffers(getEntityType());
		buffers.remove(id);
	}

	public final IAccessor initBufferByBaseLevel(String id, int level, boolean isReadonly)
	{
		DataValidator.checkForEmptyString(getEntityType(), "entityType");
		DataValidator.checkForEmptyString(id, "id");
		if (level <= 0)
		{
			throw new UnsupportedOperationException("level:"+ level+"");
		}

		 java.util.Map<Integer, ICefBuffer>  buffer = getBuffers(getEntityType()).get(id);

		ICefBuffer upperbuffer =getMaxLevelBuffer(buffer);

		CefBuffer result = new CefBuffer(createAccessor(upperbuffer.getData(), isReadonly));
		buffer.put(level, result);

		return result.getData();
	}

	private  ICefBuffer getMaxLevelBuffer(java.util.Map<Integer, ICefBuffer> buffer)
	{
		int value = 0;
		for (Map.Entry<Integer,ICefBuffer> enrity:buffer.entrySet())
		{
			if(enrity.getKey()>value)
				value=enrity.getKey();
		}
		return  buffer.get(value);
	}

	private  Integer getMaxLevel(java.util.Map<Integer, ICefBuffer> buffer)
	{
		int value = 0;
		for (Map.Entry<Integer,ICefBuffer> enrity:buffer.entrySet())
		{
			if(enrity.getKey()>value)
				value=enrity.getKey();
		}
		return value;
	}

	public final IAccessor initBufferByLevel(IEntityData data, int level, boolean isReadonly)
	{
		DataValidator.checkForNullReference(data, "data");
		DataValidator.checkForEmptyString(data.getID(), "data.ID");

		java.util.Map<String, java.util.Map<Integer, ICefBuffer>> buffers = getBuffers(getEntityType());
		java.util.Map<Integer, ICefBuffer> existing =buffers.get(data.getID());
		if(existing!=null&&existing.isEmpty()==false)
			throw new UnsupportedOperationException();

		CefBuffer buffer = new CefBuffer(createAccessor(data, isReadonly));
		java.util.HashMap<Integer, ICefBuffer> levels = new java.util.HashMap<Integer, ICefBuffer>();
		levels.put(level, buffer);
		buffers.put(data.getID(),levels);
		return buffer.getData();
	}

	private CefBuffer getCefBuffer(String dataId, int level)
	{
		DataValidator.checkForEmptyString(dataId, "dataId");
		ICefBuffer buffer = null;
		java.util.Map<String, java.util.Map<Integer, ICefBuffer>> buffers = getBuffers(getEntityType());
		java.util.Map<Integer, ICefBuffer> i = buffers.get(dataId);
		if(i != null)
			return (CefBuffer) i.get(level);
		else
			return null;
	}

	public final IAccessor getBuffer(String dataId, int level) {
		CefBuffer cefBuffer= getCefBuffer(dataId,level);
		if(cefBuffer!=null)
			return cefBuffer.getData();
		return null;
	}

	public final IAccessor getBuffer(String dataId)
	{
		DataValidator.checkForEmptyString(getEntityType(), "entityType");
		DataValidator.checkForEmptyString(dataId, "dataId");

		java.util.Map<String, java.util.Map<Integer, ICefBuffer>> buffers = getBuffers(getEntityType());
		java.util.Map<Integer, ICefBuffer> buffer = buffers.get(dataId);
		if(buffer==null)
			return null;
		return getMaxLevelBuffer(buffer).getData();
	}

	public final IAccessor acceptChange(String dataId, int level, IChangeDetail change)
	{
		DataValidator.checkForEmptyString(dataId, "dataId");
		DataValidator.checkForNullReference(change, "change");

		java.util.Map<Integer, ICefBuffer> buffers = getBuffers(getEntityType()).get(dataId);

		Integer maxKey = getMaxLevel(buffers);
		if (maxKey != level)
		{
			throw new UnsupportedOperationException("level"+ level+ "只能往最外层buffer合并变更");
		}

		IAccessor rez;
		switch (change.getChangeType())
		{
			case Modify:
				rez = buffers.get(maxKey).getData();
				rez.acceptChange(change);
				break;
			case Deleted:
				((CefBuffer)buffers.get(maxKey)).setData(null);
				rez = null;
				break;
      case Added:
				CefBuffer maxBuffer = (CefBuffer) buffers.get(maxKey);
				if (maxBuffer.getData() != null) {
          throw new CefException("maxBuffer数据位空，请联系管理员");
        }
        rez =createAccessor((IAccessor) ((AddChangeDetail) change).getEntityData().copy(), maxBuffer.getIsReadonly());
        ((CefBuffer) buffers.get(maxKey)).setData(rez);
        break;
			default:
				throw new UnsupportedOperationException("change.ChangeType"+ String.valueOf(change.getChangeType())+ "ChangeType Not Supported");
		}
		return rez;
	}

	public final IAccessor accept(String dataId, int level, IChangeDetail change)
	{
		DataValidator.checkForEmptyString(dataId, "dataId");
		DataValidator.checkForNullReference(change, "change");
		if (level == 0)
		{
			throw new UnsupportedOperationException("level"+ level+"");
		}

		IEntityData sourceAccessor = (IEntityData) getBuffer(dataId, level);
		IEntityData targetAccessor = (IEntityData) getBuffer(dataId, level - 1);
		RefObject<IEntityData> tempRef_targetAccessor = new RefObject<IEntityData>(targetAccessor);
		EntityDataManager.getInstance().acceptChanges(getAccessorCreator(), sourceAccessor, tempRef_targetAccessor, change);
		targetAccessor = tempRef_targetAccessor.argvalue;

		getBuffers(getEntityType()).get(dataId).put(level - 1, new CefBuffer((IAccessor)targetAccessor));
		return (IAccessor)targetAccessor;
	}

	public final IAccessor reject(String dataId, int level, IChangeDetail change)
	{
		DataValidator.checkForEmptyString(dataId, "dataId");
		DataValidator.checkForNullReference(change, "change");
		if (level == 0)
		{
			throw new UnsupportedOperationException("level"+ level+"");
		}

		CefBuffer sourceBuffer = getCefBuffer(dataId, level);
		IEntityData sourceData = (IEntityData)sourceBuffer.getData();
		IAccessor targetAccessor = getBuffer(dataId, level - 1);
		RefObject<IEntityData> tempRef_sourceData = new RefObject<IEntityData>(sourceData);
		EntityDataManager.getInstance().rejectChanges(getAccessorCreator(), tempRef_sourceData, (IEntityData)targetAccessor, change, sourceBuffer.getIsReadonly());
		sourceData = tempRef_sourceData.argvalue;
		getBuffers(getEntityType()).get(dataId).put(level, new CefBuffer((IAccessor)sourceData));

		return (IAccessor)sourceData;
	}

	public final void remove(String dataId){
		java.util.Map<String, java.util.Map<Integer, ICefBuffer>> buffers = getBuffers(getEntityType());
		buffers.remove(dataId);
	}

	protected java.util.Map<String, java.util.Map<Integer, ICefBuffer>> getBuffers(String entityType)
	{
		ICefSessionItem sessionItem = getSession().getSessionItems().get(entityType);
		if (sessionItem == null)
		{
			throw new RuntimeException();
		}
		return sessionItem.getBuffers();

	}

	protected IAccessor createAccessor(ICefData data, boolean isReadonly) {
		//tfs453708
		if (data instanceof IAccessor && ((IAccessor) data).getIsReadonly()
				&& ((IAccessor) data).getInnerData() != null) {
			data = ((IAccessor) data).getInnerData();
		}
		if (isReadonly)
			return getAccessorCreator().createReadonlyAccessor((data));
		return getAccessorCreator().createAccessor(data);
	}
}
